package com.warrantyhotel.android.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URISyntaxException;
import java.net.URL;

import javax.net.ssl.SSLException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.params.ConnManagerPNames;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;

import android.net.Uri;
import android.util.Log;

/**
 * This class manages connection to server and have methods to communicate with
 * it via POST and GET methods. Also there are methods that parse response from
 * server.
 */
public class HttpConnector {
	private static final String TAG = HttpConnector.class.getSimpleName();
	public final static String BASE_URL = "sandbox.warrantyhotel.com";
//	 public final static String BASE_URL = "services.warrantyhotel.com";

	private final String SUB_URL = "/JSON.svc/";

	private static HttpConnector instance = null;
	private HttpClient mClient;

	private HttpConnector() {
		final HttpParams params = new BasicHttpParams();
		params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
		params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30));
		// params.setParameter(ConnManagerPNames.TIMEOUT, 9000);
		params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
		HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
		HttpProtocolParams.setContentCharset(params, "UTF-8");
		HttpConnectionParams.setConnectionTimeout(params, 9000);
		HttpConnectionParams.setSoTimeout(params, 9000);

		// SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
		// final SchemeRegistry registry = new SchemeRegistry();
		// registry.register(new Scheme("http",
		// PlainSocketFactory.getSocketFactory(), 80));
		// registry.register(new Scheme("https",
		// SSLSocketFactory.getSocketFactory(), 443));

		SchemeRegistry registry = new SchemeRegistry();
		registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
		final SSLSocketFactory sslSocketFactory = SSLSocketFactory.getSocketFactory();
		sslSocketFactory.setHostnameVerifier(SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
		registry.register(new Scheme("https", sslSocketFactory, 443));

		final ThreadSafeClientConnManager manager = new ThreadSafeClientConnManager(params, registry);

		mClient = new DefaultHttpClient(manager, params);

	};

	public static HttpConnector getInstance() {
		if (instance == null)
			instance = new HttpConnector();
		return instance;
	}

	/**
	 * 
	 * Sends POST request to server using current url with body
	 * 
	 * @param url
	 * @param body
	 * @return
	 * @throws URISyntaxException
	 * @throws ClientProtocolException
	 * @throws IOException
	 */

	public String uploadImage(String url1, String body) {
		InputStream myInputStream = null;
		// StringBuilder sb = new StringBuilder();
		// adding some data to send along with the request to the server
		// sb.append("name=Anthony");
		URL url;
		try {
			url = new URL("https://" + BASE_URL + SUB_URL + url1);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setDoOutput(true);
			conn.setDoInput(true);
			conn.setRequestMethod("POST");
			// conn.setRequestProperty("Connection", "Keep-Alive");
			conn.setRequestProperty("Content-Type", "application/json");
			conn.setConnectTimeout(10 * 1000);

			OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
			// this is were we're adding post data to the request
			wr.write(body);
			wr.flush();
			myInputStream = conn.getInputStream();
			wr.close();
		} catch (SSLException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
			Log.d(TAG, e.getMessage());
		}

		BufferedReader reader = null;
		final StringBuffer sb = new StringBuffer("");

		try {
			reader = new BufferedReader(new InputStreamReader(myInputStream));
			String line;
			while ((line = reader.readLine()) != null) {
				sb.append(line).append("\n");
			}

		} catch (final IOException e) {
			e.printStackTrace();
		} finally {
			try {
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return sb.toString();

	}

	public String sendPostRequest(final String url, final String body) throws URISyntaxException, ClientProtocolException, IOException {
		String result = null;

		Uri.Builder builder = new Uri.Builder();
		builder.path(SUB_URL);
		builder.appendPath(url);

		final HttpPost post = new HttpPost(builder.build().toString());
		final StringEntity sEntity = new StringEntity(body, "UTF-8");
		post.setEntity(sEntity);
		post.setHeader("Content-Type", "application/json");
		try {
			result = executePostRequest(post);
		} catch (IOException e) {
			Log.e(TAG, "Exception", e);
		}

		return result;
	}

	/**
	 * 
	 * @param post
	 * @return
	 * @throws IOException
	 */

	private String executePostRequest(HttpPost post) throws IOException {
		String result = null;
		HttpEntity entity = null;
		HttpHost host = new HttpHost(BASE_URL, 443, "https");
		try {
			final HttpResponse response = mClient.execute(host, post);
			Log.v("Server response Code", "" + response.getStatusLine().getStatusCode());
			Log.v("Server Reason Phrase", "" + response.getStatusLine().getReasonPhrase());
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {

				result = readHttpResponse(response);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (entity != null) {
				entity.consumeContent();
			}
		}
		return result;
	}

	/**
	 * Sends GET request to server using current url
	 * 
	 * @param url
	 * @param useFullPathUrl
	 * @return
	 * @throws URISyntaxException
	 * @throws ClientProtocolException
	 * @throws IOException
	 */

	public String sendGETRequest(final String url) throws URISyntaxException, ClientProtocolException, IOException {
		String result = null;

		Uri.Builder builder = new Uri.Builder();
		builder.path(SUB_URL);
		builder.appendPath(url);
		final HttpGet get = new HttpGet(builder.build().toString());
		// final HttpGet get = new HttpGet(SUB_URL + url);

		try {
			result = executeRequest(get);
		} catch (IOException e) {
			Log.e(TAG, "Exception", e);
		}

		return result;
	}

	private String executeRequest(HttpGet get) throws IOException {
		String result = null;
		HttpEntity entity = null;
		HttpHost host = new HttpHost(BASE_URL, 443, "https");
		try {
			final HttpResponse response = mClient.execute(host, get);
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {

				result = readHttpResponse(response);
			}
		} finally {
			if (entity != null) {
				entity.consumeContent();
			}
		}
		return result;
	}

	/**
	 * Reads http-response from server and converts it into String
	 * 
	 * @param response
	 *            - Response from server
	 * @return string representation of a response
	 */
	private String readHttpResponse(final HttpResponse response) {
		BufferedReader reader = null;
		final StringBuffer sb = new StringBuffer("");

		try {
			reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
			String line;
			while ((line = reader.readLine()) != null) {
				sb.append(line).append("\n");
			}

		} catch (final IOException e) {
			e.printStackTrace();
		} finally {
			try {
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return sb.toString();
	}

	/**
	 * Retrieving location via address
	 * 
	 * @param get
	 *            The GET request to executed.
	 * @param handler
	 *            The handler which will parse the response.
	 * 
	 * @throws IOException
	 */

	private String executeRequestLocation(HttpGet get) throws IOException {
		String result = null;
		HttpEntity entity = null;
		HttpHost host = new HttpHost("maps.google.com", 80, "http");
		try {
			final HttpResponse response = mClient.execute(host, get);
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				result = readHttpResponse(response);
			}
		} finally {
			if (entity != null) {
				entity.consumeContent();
			}
		}
		return result;
	}

	/**
	 * sendGETRequestLocation
	 * 
	 * @param url
	 * @return
	 * @throws URISyntaxException
	 * @throws ClientProtocolException
	 * @throws IOException
	 */

	public String sendGETRequestLocation(final String url) throws URISyntaxException, ClientProtocolException, IOException {
		String result = null;

		Uri.Builder builder = new Uri.Builder();
		builder.appendPath(url);

		final HttpGet get = new HttpGet(url);

		try {
			result = executeRequestLocation(get);
		} catch (IOException e) {
			Log.e(TAG, "Location Exception", e);
		}
		return result;
	}

}
